home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / quicktime / quicktime vr / vrscript / common files / qtvrutilities.c < prev    next >
Encoding:
Text File  |  2000-06-23  |  32.2 KB  |  1,132 lines

  1. //////////
  2. //
  3. //    File:        QTVRUtilities.c
  4. //
  5. //    Contains:    Some utilities for working with QuickTime VR movies.
  6. //                All utilities start with the prefix "QTVRUtils_".
  7. //
  8. //    Written by:    Tim Monroe
  9. //
  10. //    Copyright:    © 1996-1998 by Apple Computer, Inc., all rights reserved.
  11. //
  12. //    Change History (most recent first):
  13. //
  14. //       <25>         04/15/99    rtm        added QTVRUtils_PanAngleToPoint3D, from Bryce Wolfson
  15. //       <24>         04/05/99    rtm        added QTVRUtils_IsBackBufferHorizontal
  16. //       <23>         03/11/99    rtm        moved _GetControllerType and _SetControllerType to QTUtilities
  17. //       <22>         02/03/99    rtm        moved non-QTVR-specific utilities to QTUtilities
  18. //       <21>         02/12/98    rtm        added QTVRUtils_HideHotSpotNames and her sisters, *Show* and *Toggle*
  19. //       <20>         01/27/98    rtm        revised QTVRUtils_IsQTVRMgrInstalled and QTVRUtils_GetQTVRVersion
  20. //       <19>         01/26/98    rtm        revised QTVRUtils_GetHotSpotName to look also in hot spot atom for name atom
  21. //       <18>         01/14/98    rtm        added QTVRUtils_SetControllerType and QTVRUtils_AddStr255ToAtomContainer
  22. //       <17>         10/20/97    rtm        added QTVRUtils_IsMultiNode; added Endian*_BtoN macros to file format routines
  23. //       <16>         10/17/97    rtm        fixed QTVRUtils_IsControllerButtonVisible behavior for speaker button
  24. //       <15>         10/07/97    rtm        added cannotFindAtomErr result code to QTVRUtils_Get*AtomData functions
  25. //       <14>         09/15/97    rtm        added QTVRUtils_ToggleControllerBar
  26. //       <13>         08/21/97    rtm        added QTVRUtils_IsControllerButtonVisible
  27. //       <12>         08/19/97    rtm        added #ifdefs to support Windows compilation
  28. //       <11>         08/05/97    rtm        added QTVRUtils_GetNodeComment; still needs testing
  29. //       <10>         07/27/97    rtm        fixed QTVRUtils_GetHotSpotCount; added QTVRUtils_GetHotSpotIDByIndex
  30. //       <9>         07/25/97    rtm        revised QTVRUtils_Get*AtomData functions to use QTCopyAtomDataToPtr;
  31. //                                    rewrote QTVRUtils_GetStringFromAtom
  32. //       <8>         07/24/97    rtm        removed sound volume utilities; added QTVRUtils_IsZoomAvailable;
  33. //                                    revised QTVRUtils_IsQTVRMovie to use GetUserDataItem, not GetUserData
  34. //       <7>         07/23/97    rtm        revised file format utilities; added QTVRUtils_Get*AtomData functions
  35. //       <6>         07/22/97    rtm        fixed QTVRUtils_GetHotSpotCount to make sure handle is actually resized
  36. //       <5>         07/21/97    rtm        added QTVRUtils_GetNodeCount
  37. //       <4>         06/04/97    rtm        fixed QTVRUtils_ShowControllerButton and QTVRUtils_HideControllerButton,
  38. //                                    and added some explanation of them; added QTVRUtils_ResetControllerButton
  39. //       <3>         02/03/97    rtm        revised QTVRUtils_ShowControllerButton and QTVRUtils_HideControllerButton 
  40. //                                    to use explicit flag
  41. //       <2>         12/03/96    rtm        added controller bar utilities
  42. //       <1>         11/27/96    rtm        first file
  43. //       
  44. //////////
  45.  
  46. //////////
  47. //
  48. // header files
  49. //
  50. //////////
  51.  
  52. #ifndef __QTVRUtilities__
  53. #include "QTVRUtilities.h"
  54. #endif
  55.  
  56. #ifndef __QTUtilities__
  57. #include "QTUtilities.h"
  58. #endif
  59.  
  60. #include <math.h>
  61. #include <stdlib.h>
  62. #include <string.h>
  63.  
  64.  
  65.  
  66. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  67. //
  68. // General utilities.
  69. //
  70. // Use these functions to get information about the availability/features of QuickTime VR or other services.
  71. //
  72. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  73.  
  74. //////////
  75. //
  76. // QTVRUtils_IsQTVRMgrInstalled
  77. // Is the QuickTime VR Manager installed?
  78. //
  79. //////////
  80.  
  81. Boolean QTVRUtils_IsQTVRMgrInstalled (void) 
  82. {
  83.     Boolean     myQTVRAvail = false;
  84.     long        myAttrs;
  85.     OSErr         myErr = noErr;
  86.  
  87.     myErr = Gestalt(gestaltQTVRMgrAttr, &myAttrs);
  88.     if (myErr == noErr)
  89.         if (myAttrs & (1L << gestaltQTVRMgrPresent))
  90.             myQTVRAvail = true;
  91.  
  92.     return(myQTVRAvail);
  93. }
  94.  
  95.  
  96. //////////
  97. //
  98. // QTVRUtils_GetQTVRVersion
  99. // Get the version of the QuickTime VR Manager installed.
  100. //
  101. // The low-order word of the returned long integer contains the version number,
  102. // so you can test a version like this:
  103. //
  104. //        if (QTVRUtils_GetQTVRVersion() < 0x0210)        // we require QTVR 2.1 or greater
  105. //            return;
  106. //
  107. //////////
  108.  
  109. long QTVRUtils_GetQTVRVersion (void)
  110. {
  111.     long         myVersion = 0L;
  112.     OSErr         myErr = noErr;
  113.  
  114.     myErr = Gestalt(gestaltQTVRMgrVers, &myVersion);
  115.     if (myErr == noErr)
  116.         return(myVersion);
  117.     else
  118.         return(0L);
  119. }
  120.  
  121.  
  122. //////////
  123. //
  124. // QTVRUtils_IsQTVRMovie
  125. // Is the specified movie a QTVR movie?
  126. //
  127. // WARNING: This function is intended for use ONLY when you want to determine if you've got a QTVR movie
  128. // but you don't want to use the QuickTime VR API (perhaps QTVR isn't installed...). The preferred way to
  129. // determine if a movie is a QTVR movie is to call QTVRGetQTVRTrack and then QTVRGetQTVRInstance; if you
  130. // get back a non-NULL instance, you've got a QTVR movie.
  131. //
  132. //////////
  133.  
  134. Boolean QTVRUtils_IsQTVRMovie (Movie theMovie) 
  135. {
  136.     Boolean            myIsQTVRMovie = false;
  137.     OSType            myType;
  138.     
  139.     // QTVR movies have a special piece of user data identifying the movie controller type
  140.     myType = QTUtils_GetControllerType(theMovie);
  141.     
  142.     if ((myType == kQTVRQTVRType) || (myType == kQTVROldPanoType) || (myType == kQTVROldObjectType))
  143.         myIsQTVRMovie = true; 
  144.         
  145.     return(myIsQTVRMovie);
  146. }
  147.  
  148.  
  149. //////////
  150. //
  151. // QTVRUtils_Is20QTVRMovie
  152. // Is the specified QTVR movie version 2.0 or greater?
  153. //
  154. //////////
  155.  
  156. Boolean QTVRUtils_Is20QTVRMovie (Movie theMovie) 
  157. {
  158.     Boolean            myIs20QTVRMovie = false;
  159.     OSType            myType;
  160.     
  161.     // QTVR movies have a special piece of user data identifying the movie controller type
  162.     myType = QTUtils_GetControllerType(theMovie);
  163.     
  164.     if (myType == kQTVRQTVRType)
  165.         myIs20QTVRMovie = true; 
  166.         
  167.     return(myIs20QTVRMovie);
  168. }
  169.  
  170.  
  171. //////////
  172. //
  173. // QTVRUtils_IsTranslateAvailable
  174. // Is translation currently enabled for the specified object node?
  175. //
  176. //////////
  177.  
  178. Boolean QTVRUtils_IsTranslateAvailable (QTVRInstance theInstance) 
  179. {
  180.     Boolean        myState;
  181.     
  182.     QTVRGetControlSetting(theInstance, kQTVRTranslation, &myState);
  183.     return(myState);
  184. }
  185.  
  186.  
  187. //////////
  188. //
  189. // QTVRUtils_IsZoomAvailable
  190. // Is zooming currently enabled for the specified object node?
  191. //
  192. //////////
  193.  
  194. Boolean QTVRUtils_IsZoomAvailable (QTVRInstance theInstance) 
  195. {
  196.     Boolean        myState;
  197.     
  198.     QTVRGetControlSetting(theInstance, kQTVRCanZoom, &myState);
  199.     return(myState);
  200. }
  201.  
  202.  
  203. //////////
  204. //
  205. // QTVRUtils_IsPanoNode
  206. // Is the specified node a panoramic node?
  207. //
  208. //////////
  209.  
  210. Boolean QTVRUtils_IsPanoNode (QTVRInstance theInstance) 
  211. {
  212.     return(QTVRGetNodeType(theInstance, kQTVRCurrentNode) == kQTVRPanoramaType);
  213. }
  214.  
  215.  
  216. //////////
  217. //
  218. // QTVRUtils_IsObjectNode
  219. // Is the specified node an object node?
  220. //
  221. //////////
  222.  
  223. Boolean QTVRUtils_IsObjectNode (QTVRInstance theInstance) 
  224. {
  225.     return(QTVRGetNodeType(theInstance, kQTVRCurrentNode) == kQTVRObjectType);
  226. }
  227.  
  228.  
  229. //////////
  230. //
  231. // QTVRUtils_IsHotSpotInNode
  232. // Does the specified node contain at least one hot spot (whether visible, enabled, or whatever)?
  233. //
  234. // NOTE: This is not an easy function to implement using just the QTVR 2.1 API. We do have our own
  235. // utility QTVRUtils_GetHotSpotCount, but that function returns the number of hot spot information atoms
  236. // in the node, which is not (necessarily) the number of hot spot regions in the hot spot image track.
  237. // For panoramas, we could check to see if the panorama sample atom structure contains a reference
  238. // to a hot spot image track; if it does, we'd blindly assume that that track isn't empty. For objects,
  239. // we'll have to rely on QTVRUtils_GetHotSpotCount. So it goes....
  240. //
  241. // In an ideal world, there would be a hot spot information atom for each and every hot spot region in
  242. // the hot spot image track, in which case we could be happier using QTVRUtils_GetHotSpotCount.
  243. //
  244. //////////
  245.  
  246. Boolean QTVRUtils_IsHotSpotInNode (QTVRInstance theInstance) 
  247. {
  248.     return(QTVRUtils_GetHotSpotCount(theInstance, QTVRGetCurrentNodeID(theInstance), NULL) > 0);
  249. }
  250.  
  251.  
  252. //////////
  253. //
  254. // QTVRUtils_IsMultiNode
  255. // Does the specified QuickTime VR instance contain more than one node?
  256. //
  257. //////////
  258.  
  259. Boolean QTVRUtils_IsMultiNode (QTVRInstance theInstance) 
  260. {
  261.     return(QTVRUtils_GetNodeCount(theInstance) > (UInt32)1);
  262. }
  263.  
  264.  
  265. //////////
  266. //
  267. // QTVRUtils_IsBackBufferHorizontal
  268. // Is the back buffer oriented horizontally?
  269. //
  270. //////////
  271.  
  272. Boolean QTVRUtils_IsBackBufferHorizontal (QTVRInstance theInstance)
  273. {
  274.     UInt32        myGeometry;
  275.     UInt16        myResolution;
  276.     UInt32        myCachePixelFormat;
  277.     SInt16        myCacheSize;
  278.     OSErr        myErr = noErr;
  279.  
  280.     if (theInstance == NULL)
  281.         return(false);
  282.  
  283.     myErr = QTVRGetBackBufferSettings(theInstance, &myGeometry, &myResolution, &myCachePixelFormat, &myCacheSize);
  284.     if (myErr != noErr)
  285.         return(false);
  286.     else
  287.         return(myGeometry == kQTVRHorizontalCylinder);
  288. }
  289.  
  290.  
  291. //////////
  292. //
  293. // QTVRUtils_HideHotSpotNames
  294. // Disable the displaying of hot spot names in the controller bar.
  295. //
  296. //////////
  297.  
  298. void QTVRUtils_HideHotSpotNames (MovieController theMC) 
  299. {
  300.     QTUtils_HideControllerButton(theMC, kQTVRHotSpotNames);
  301. }
  302.  
  303.  
  304. //////////
  305. //
  306. // QTVRUtils_ShowHotSpotNames
  307. // Enable the displaying of hot spot names in the controller bar.
  308. //
  309. //////////
  310.  
  311. void QTVRUtils_ShowHotSpotNames (MovieController theMC) 
  312. {
  313.     QTUtils_ShowControllerButton(theMC, kQTVRHotSpotNames);
  314. }
  315.  
  316.  
  317. //////////
  318. //
  319. // QTVRUtils_ToggleHotSpotNames
  320. // Toggle the displaying of hot spot names in the controller bar.
  321. //
  322. //////////
  323.  
  324. void QTVRUtils_ToggleHotSpotNames (MovieController theMC) 
  325. {
  326.     QTUtils_ToggleControllerButton(theMC, kQTVRHotSpotNames);
  327. }
  328.  
  329.  
  330. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  331. //
  332. // File format utilities.
  333. //
  334. // Use these functions to read information from QuickTime VR files that's not accessible using the API.
  335. // Throughout, we assume that we're dealing with format 2.0 files. We begin with a series of functions that
  336. // return a pointer to the data in an atom (QTVRUtils_Get*AtomData); you probably won't use these functions
  337. // directly.
  338. //
  339. // Keep in mind that data stored in QuickTime atoms is big-endian. We'll need to convert any multi-byte data
  340. // that we read from an atom to native format before we use it.
  341. //
  342. // Note that these file format utilities are all Getters. As yet, no Setters. Perhaps later?
  343. //
  344. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  345.  
  346. //////////
  347. //
  348. // QTVRUtils_GetVRWorldHeaderAtomData
  349. // Get a pointer to the VR world header atom data in a QTVR movie.
  350. //
  351. //////////
  352.  
  353. OSErr QTVRUtils_GetVRWorldHeaderAtomData (QTVRInstance theInstance, QTVRWorldHeaderAtomPtr theVRWorldHdrAtomPtr)
  354. {
  355.     QTAtomContainer            myVRWorld;
  356.     QTAtom                    myAtom;
  357.     OSErr                    myErr = noErr;
  358.         
  359.     // get the VR world
  360.     myErr = QTVRGetVRWorld(theInstance, &myVRWorld);
  361.     if (myErr != noErr)
  362.         return(myErr);
  363.     
  364.     // get the single VR world header atom in the VR world
  365.     myAtom = QTFindChildByIndex(myVRWorld, kParentAtomIsContainer, kQTVRWorldHeaderAtomType, 1, NULL);
  366.     if (myAtom != 0)
  367.         myErr = QTCopyAtomDataToPtr(myVRWorld, myAtom, false, sizeof(QTVRWorldHeaderAtom), theVRWorldHdrAtomPtr, NULL);
  368.     else 
  369.         myErr = cannotFindAtomErr;
  370.     
  371.     QTDisposeAtomContainer(myVRWorld);
  372.     return(myErr);
  373. }
  374.  
  375.  
  376. //////////
  377. //
  378. // QTVRUtils_GetNodeHeaderAtomData
  379. // Get a pointer to the node header atom data for the node having the specified node ID.
  380. //
  381. //////////
  382.  
  383. OSErr QTVRUtils_GetNodeHeaderAtomData (QTVRInstance theInstance, UInt32 theNodeID, QTVRNodeHeaderAtomPtr theNodeHdrPtr)
  384. {
  385.     QTAtomContainer            myNodeInfo;
  386.     QTAtom                    myAtom;
  387.     OSErr                    myErr = noErr;
  388.         
  389.     // get the node information atom container for the specified node
  390.     myErr = QTVRGetNodeInfo(theInstance, theNodeID, &myNodeInfo);
  391.     if (myErr != noErr)
  392.         return(myErr);
  393.     
  394.     // get the single node header atom in the node information atom container
  395.     myAtom = QTFindChildByID(myNodeInfo, kParentAtomIsContainer, kQTVRNodeHeaderAtomType, 1, NULL);
  396.     if (myAtom != 0)
  397.         myErr = QTCopyAtomDataToPtr(myNodeInfo, myAtom, false, sizeof(QTVRNodeHeaderAtom), theNodeHdrPtr, NULL);
  398.     else 
  399.         myErr = cannotFindAtomErr;
  400.  
  401.     QTDisposeAtomContainer(myNodeInfo);
  402.     return(myErr);
  403. }
  404.  
  405.  
  406. //////////
  407. //
  408. // QTVRUtils_GetHotSpotAtomData
  409. // Get a pointer to the hot spot atom data for hot spot having the specified hot spot ID in the specified node.
  410. //
  411. //////////
  412.  
  413. OSErr QTVRUtils_GetHotSpotAtomData (QTVRInstance theInstance, UInt32 theNodeID, UInt32 theHotSpotID, QTVRHotSpotInfoAtomPtr theHotSpotInfoPtr)
  414. {
  415.     QTAtomContainer            myNodeInfo;
  416.     QTAtom                    myHSParentAtom;
  417.     OSErr                    myErr = noErr;
  418.         
  419.     // (1) the node information atom container contains a *hot spot parent atom*;
  420.     // (2) the hot spot parent atom contains one or more *hot spot atoms*;
  421.     // (3) the hot spot atom contains two children, a *general hot spot information atom*
  422.     //     and a *specific hot spot information atom*.
  423.     // We want to return a pointer to the general hot spot information atom data.
  424.  
  425.     // get the node information atom container for the specified node
  426.     myErr = QTVRGetNodeInfo(theInstance, theNodeID, &myNodeInfo);
  427.     if (myErr != noErr)
  428.         return(myErr);
  429.     
  430.     // get the single hot spot parent atom in the node information atom container
  431.     myHSParentAtom = QTFindChildByID(myNodeInfo, kParentAtomIsContainer, kQTVRHotSpotParentAtomType, 1, NULL);
  432.     if (myHSParentAtom != 0) {
  433.         QTAtom                myHSAtom;
  434.         
  435.         // get the hot spot atom whose atom ID is the specified hot spot ID
  436.         myHSAtom = QTFindChildByID(myNodeInfo, myHSParentAtom, kQTVRHotSpotAtomType, theHotSpotID, NULL);
  437.         if (myHSAtom != 0) {
  438.             QTAtom            myAtom;
  439.             
  440.             // get the single hot spot information atom in the hot spot atom
  441.             myAtom = QTFindChildByIndex(myNodeInfo, myHSAtom, kQTVRHotSpotInfoAtomType, 1, NULL);
  442.             if (myAtom != 0) {
  443.                 myErr = QTCopyAtomDataToPtr(myNodeInfo, myAtom, false, sizeof(QTVRHotSpotInfoAtom), theHotSpotInfoPtr, NULL);
  444.             }
  445.         } else {
  446.             myErr = cannotFindAtomErr;
  447.         }
  448.     } else {
  449.         myErr = cannotFindAtomErr;
  450.     }
  451.  
  452.     QTDisposeAtomContainer(myNodeInfo);
  453.     return(myErr);
  454. }
  455.  
  456.  
  457. //////////
  458. //
  459. // QTVRUtils_GetStringFromAtom
  460. // Get the string data from the string atom having the specified ID in the specified atom container.
  461. //
  462. // We use a different strategy here, since we don't know the size of the string data in advance.
  463. //
  464. //////////
  465.  
  466. char *QTVRUtils_GetStringFromAtom (QTAtomContainer theContainer, QTAtom theParent, QTAtomID theID)
  467. {
  468.     QTVRStringAtomPtr    myStringAtomPtr = NULL;
  469.     QTAtom                myNameAtom;
  470.     char                *myString = NULL;
  471.      OSErr                myErr = noErr;
  472.  
  473.     if (theContainer == NULL)
  474.         return(myString);
  475.         
  476.     QTLockContainer(theContainer);
  477.     
  478.     myNameAtom = QTFindChildByID(theContainer, theParent, kQTVRStringAtomType, theID, NULL);
  479.     if (myNameAtom != 0) {
  480.         myErr = QTGetAtomDataPtr(theContainer, myNameAtom, NULL, (Ptr *)&myStringAtomPtr);
  481.         if ((myErr == noErr) && (myStringAtomPtr != NULL)) {
  482.             UInt16        myLength;
  483.                 
  484.             myLength = EndianU16_BtoN(myStringAtomPtr->stringLength);
  485.             if (myLength > 0) {
  486.                 myString = malloc(myLength + 1);
  487.                 if (myString != NULL) {
  488.                     memcpy(myString, myStringAtomPtr->theString, myLength);
  489.                     myString[myLength] = '\0';
  490.                 }
  491.             }            
  492.         }
  493.     }
  494.     
  495.     QTUnlockContainer(theContainer);
  496.     return(myString);
  497. }
  498.  
  499.  
  500. //////////
  501. //
  502. // QTVRUtils_AddStr255ToAtomContainer
  503. // Add a Pascal string to the specified atom container; return (through theID) the ID of the new string atom.
  504. //
  505. //////////
  506.  
  507. OSErr QTVRUtils_AddStr255ToAtomContainer (QTAtomContainer theContainer, QTAtom theParent, Str255 theString, QTAtomID *theID)
  508. {
  509.     OSErr                    myErr = noErr;
  510.  
  511.     *theID = 0;                // initialize the returned atom ID
  512.     
  513.     if ((theContainer == NULL) || (theParent == 0))
  514.         return(paramErr);
  515.         
  516.     if (theString[0] != 0) {
  517.         QTAtom                myStringAtom;
  518.         UInt16                mySize;
  519.         QTVRStringAtomPtr    myStringAtomPtr = NULL;
  520.         
  521.         mySize = sizeof(QTVRStringAtom) - 4 + theString[0] + 1;
  522.         myStringAtomPtr = (QTVRStringAtomPtr)NewPtrClear(mySize);
  523.         
  524.         if (myStringAtomPtr != NULL) {
  525.             myStringAtomPtr->stringUsage = EndianU16_NtoB(1);
  526.             myStringAtomPtr->stringLength = EndianU16_NtoB(theString[0]);
  527.             BlockMove(theString + 1, myStringAtomPtr->theString, theString[0]);
  528.             myStringAtomPtr->theString[theString[0]] = '\0';
  529.             myErr = QTInsertChild(theContainer, theParent, kQTVRStringAtomType, 0, 0, mySize, (Ptr)myStringAtomPtr, &myStringAtom);
  530.             DisposePtr((Ptr)myStringAtomPtr);
  531.             
  532.             if (myErr == noErr)
  533.                 QTGetAtomTypeAndID(theContainer, myStringAtom, NULL, theID);
  534.         }
  535.     }
  536.     
  537.     return(myErr);
  538. }
  539.  
  540.  
  541. //////////
  542. //
  543. // QTVRUtils_GetDefaultNodeID
  544. // Get the ID of the default node in a QTVR movie.
  545. //
  546. //////////
  547.  
  548. UInt32 QTVRUtils_GetDefaultNodeID (QTVRInstance theInstance)
  549. {
  550.     QTVRWorldHeaderAtom         myVRWorldHeader;
  551.     UInt32                    myNodeID = kQTVRCurrentNode;
  552.     OSErr                    myErr = noErr;
  553.         
  554.     myErr = QTVRUtils_GetVRWorldHeaderAtomData(theInstance, &myVRWorldHeader);
  555.     if (myErr == noErr)
  556.         myNodeID = EndianU32_BtoN(myVRWorldHeader.defaultNodeID);
  557.  
  558.     return(myNodeID);
  559. }
  560.  
  561.  
  562. //////////
  563. //
  564. // QTVRUtils_GetSceneFlags
  565. // Get the set of flags associated with the VR scene.
  566. // (Currently these flags are undefined, however.)
  567. //
  568. //////////
  569.  
  570. UInt32 QTVRUtils_GetSceneFlags (QTVRInstance theInstance)
  571. {
  572.     QTVRWorldHeaderAtom         myVRWorldHeader;
  573.     UInt32                    myFlags = 0L;
  574.     OSErr                    myErr;
  575.         
  576.     myErr = QTVRUtils_GetVRWorldHeaderAtomData(theInstance, &myVRWorldHeader);
  577.     if (myErr == noErr)
  578.         myFlags = EndianU32_BtoN(myVRWorldHeader.vrWorldFlags);
  579.  
  580.     return(myFlags);
  581. }
  582.  
  583.  
  584. //////////
  585. //
  586. // QTVRUtils_GetSceneName
  587. // Get the name of the VR scene.
  588. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  589. //
  590. //////////
  591.  
  592. char *QTVRUtils_GetSceneName (QTVRInstance theInstance)
  593. {
  594.     QTVRWorldHeaderAtom             myVRWorldHeader;
  595.     char                        *mySceneName = NULL;
  596.     OSErr                        myErr = noErr;
  597.         
  598.     myErr = QTVRUtils_GetVRWorldHeaderAtomData(theInstance, &myVRWorldHeader);
  599.     if (myErr == noErr) {
  600.         QTAtomID                myNameAtomID;
  601.         
  602.         // get the atom ID of the name string atom
  603.         myNameAtomID = EndianU32_BtoN(myVRWorldHeader.nameAtomID);
  604.         
  605.         if (myNameAtomID != 0) {
  606.             QTAtomContainer        myVRWorld;
  607.             
  608.             // the string atom containing the name of the scene is a *sibling* of the VR world header atom
  609.             myErr = QTVRGetVRWorld(theInstance, &myVRWorld);
  610.             if (myErr == noErr)
  611.                 mySceneName = QTVRUtils_GetStringFromAtom(myVRWorld, kParentAtomIsContainer, myNameAtomID);
  612.             
  613.             QTDisposeAtomContainer(myVRWorld);
  614.         }
  615.     }
  616.  
  617.     return(mySceneName);
  618. }
  619.  
  620.  
  621. //////////
  622. //
  623. // QTVRUtils_GetNodeCount
  624. // Get the number of nodes in a QTVR movie.
  625. //
  626. //////////
  627.  
  628. UInt32 QTVRUtils_GetNodeCount (QTVRInstance theInstance)
  629. {
  630.     QTAtomContainer            myVRWorld;
  631.     QTAtom                    myNodeParentAtom;
  632.     UInt32                    myNumNodes = 0;
  633.     OSErr                    myErr = noErr;
  634.  
  635.     // get the VR world
  636.     myErr = QTVRGetVRWorld(theInstance, &myVRWorld);
  637.     if (myErr != noErr)
  638.         return(myNumNodes);
  639.  
  640.     // get the node parent atom, whose children contain info about all nodes in the scene
  641.     myNodeParentAtom = QTFindChildByIndex(myVRWorld, kParentAtomIsContainer, kQTVRNodeParentAtomType, 1, NULL);
  642.     if (myNodeParentAtom != 0) {
  643.         // now count the node ID children of the node parent atom, which is the number of nodes in the scene
  644.         myNumNodes = QTCountChildrenOfType(myVRWorld, myNodeParentAtom, kQTVRNodeIDAtomType);
  645.     }    
  646.  
  647.     QTDisposeAtomContainer(myVRWorld);
  648.     
  649.     return(myNumNodes);
  650. }
  651.  
  652.  
  653. //////////
  654. //
  655. // QTVRUtils_GetNodeType
  656. // Get the type of the node with the specified ID.
  657. //
  658. // NOTE: This function is redundant, given QTVRGetNodeType; it's included here for illustrative purposes only.
  659. //
  660. //////////
  661.  
  662. OSErr QTVRUtils_GetNodeType (QTVRInstance theInstance, UInt32 theNodeID, OSType *theNodeType)
  663. {
  664.     QTVRNodeHeaderAtom        myNodeHeader;
  665.     OSErr                    myErr = noErr;
  666.  
  667.     // make sure we always return some meaningful value
  668.     *theNodeType = kQTVRUnknownType;
  669.     
  670.     // get the node header atom data
  671.     myErr = QTVRUtils_GetNodeHeaderAtomData(theInstance, theNodeID, &myNodeHeader);
  672.     if (myErr == noErr)
  673.         *theNodeType = EndianU32_BtoN(myNodeHeader.nodeType);
  674.         
  675.     return(myErr);
  676. }
  677.  
  678.  
  679. //////////
  680. //
  681. // QTVRUtils_GetNodeName
  682. // Get the name of the node with the specified ID.
  683. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  684. //
  685. //////////
  686.  
  687. char *QTVRUtils_GetNodeName (QTVRInstance theInstance, UInt32 theNodeID)
  688. {
  689.     QTVRNodeHeaderAtom        myNodeHeader;
  690.     char                    *myNodeName = NULL;
  691.     OSErr                    myErr = noErr;
  692.     
  693.     myErr = QTVRUtils_GetNodeHeaderAtomData(theInstance, theNodeID, &myNodeHeader);
  694.     if (myErr == noErr) {
  695.         QTAtomID                myNameAtomID;
  696.         
  697.         // get the atom ID of the name string atom
  698.         myNameAtomID = EndianU32_BtoN(myNodeHeader.nameAtomID);
  699.         
  700.         if (myNameAtomID != 0) {
  701.             QTAtomContainer        myNodeInfo;
  702.             
  703.             // the string atom containing the name of the node is a *sibling* of the node information atom
  704.             myErr = QTVRGetNodeInfo(theInstance, theNodeID, &myNodeInfo);
  705.             if (myErr == noErr)
  706.                 myNodeName = QTVRUtils_GetStringFromAtom(myNodeInfo, kParentAtomIsContainer, myNameAtomID);
  707.  
  708.             QTDisposeAtomContainer(myNodeInfo);
  709.         }
  710.     }
  711.     
  712.     return(myNodeName);
  713. }
  714.  
  715.  
  716. //////////
  717. //
  718. // QTVRUtils_GetNodeComment
  719. // Get the comment for the node with the specified ID.
  720. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  721. //
  722. //////////
  723.  
  724. char *QTVRUtils_GetNodeComment (QTVRInstance theInstance, UInt32 theNodeID)
  725. {
  726.     QTVRNodeHeaderAtom        myNodeHeader;
  727.     char                    *myNodeCmt = NULL;
  728.     OSErr                    myErr = noErr;
  729.     
  730.     myErr = QTVRUtils_GetNodeHeaderAtomData(theInstance, theNodeID, &myNodeHeader);
  731.     if (myErr == noErr) {
  732.         QTAtomID                myCmtAtomID;
  733.         
  734.         // get the atom ID of the comment string atom
  735.         myCmtAtomID = EndianU32_BtoN(myNodeHeader.commentAtomID);
  736.         
  737.         if (myCmtAtomID != 0) {
  738.             QTAtomContainer        myNodeInfo;
  739.             
  740.             // the string atom containing the comment for the node is a *sibling* of the node information atom
  741.             myErr = QTVRGetNodeInfo(theInstance, theNodeID, &myNodeInfo);
  742.             if (myErr == noErr)
  743.                 myNodeCmt = QTVRUtils_GetStringFromAtom(myNodeInfo, kParentAtomIsContainer, myCmtAtomID);
  744.  
  745.             QTDisposeAtomContainer(myNodeInfo);
  746.         }
  747.     }
  748.     
  749.     return(myNodeCmt);
  750. }
  751.  
  752.  
  753. //////////
  754. //
  755. // QTVRUtils_GetHotSpotCount
  756. // Return the number of hot spots in the node with specified ID,
  757. // and fill the specified handle with a list of the hot spot IDs.
  758. //
  759. // If theHotSpotIDs == NULL on entry, do not pass back the list of IDs.
  760. //
  761. // WARNING: This routine determines the number of hot spots by counting
  762. // the hot spot atoms in a hot spot parent atom; this might not be
  763. // the same as counting the number of regions in the hot spot image track.
  764. // Sigh.
  765. //
  766. //////////
  767.  
  768. UInt32 QTVRUtils_GetHotSpotCount (QTVRInstance theInstance, UInt32 theNodeID, Handle theHotSpotIDs)
  769. {
  770.     QTAtomContainer            myNodeInfo;
  771.     QTAtom                    myHSParentAtom = 0;
  772.     UInt32                    myNumHotSpots = 0;
  773.     OSErr                    myErr = noErr;
  774.     
  775.     // get the node information atom container for the current node
  776.     myErr = QTVRGetNodeInfo(theInstance, theNodeID, &myNodeInfo);
  777.     
  778.     // get the hot spot parent atom
  779.     if (myErr == noErr)
  780.         myHSParentAtom = QTFindChildByID(myNodeInfo, kParentAtomIsContainer, kQTVRHotSpotParentAtomType, 1, NULL);
  781.         
  782.     if (myHSParentAtom != 0) {
  783.         SignedByte            myHState;
  784.         Size                mySize;
  785.  
  786.         // get the number of hot spots in the current node
  787.         myNumHotSpots = QTCountChildrenOfType(myNodeInfo, myHSParentAtom, kQTVRHotSpotAtomType);
  788.         
  789.         // now pass back a list of the hot spot IDs;
  790.         // if theHotSpotIDs is NULL on entry, we assume the caller doesn't want this information
  791.         if (theHotSpotIDs != NULL) {
  792.         
  793.             // unlock the handle, if it's locked (so that we can resize it)
  794.             myHState = HGetState(theHotSpotIDs);
  795.             if (myHState & 0x80)            // 0x80 == the block-is-locked bit in the SignedByte returned by HGetState
  796.                 HUnlock(theHotSpotIDs);
  797.  
  798.             // resize the handle to the appropriate size
  799.             mySize = sizeof(UInt32) * myNumHotSpots;
  800.             SetHandleSize(theHotSpotIDs, mySize);
  801.             
  802.             // restore the original handle state
  803.             HSetState(theHotSpotIDs, myHState);
  804.             
  805.             // make sure we actually did resize the handle
  806.             if (GetHandleSize(theHotSpotIDs) == mySize) {
  807.                 short            myIndex;
  808.                 QTAtom            myAtom;
  809.                 QTAtomID        myID;
  810.                 UInt32            *myIDPtr;
  811.                 
  812.                 myIDPtr = (UInt32 *)*theHotSpotIDs;
  813.  
  814.                 // loop thru all the hot spots to get their IDs
  815.                 for (myIndex = 1; myIndex <= (short)myNumHotSpots; myIndex++) {
  816.                     myAtom = QTFindChildByIndex(myNodeInfo, myHSParentAtom, kQTVRHotSpotAtomType, myIndex, &myID);
  817.                     myIDPtr[myIndex - 1] = (UInt32)myID;
  818.                 }
  819.             }
  820.         }
  821.     }
  822.     
  823.     QTDisposeAtomContainer(myNodeInfo);
  824.     return(myNumHotSpots);
  825. }
  826.  
  827.  
  828. //////////
  829. //
  830. // QTVRUtils_GetHotSpotIDByIndex
  831. // Return the hot spot ID having the specified index in the list of hot spot IDs returned by QTVRUtils_GetHotSpotCount,
  832. // or kQTVRUtils_InvalidHotSpotID if no such hot spot exists.
  833. //
  834. //////////
  835.  
  836. UInt32 QTVRUtils_GetHotSpotIDByIndex (QTVRInstance theInstance, Handle theHotSpotIDs, UInt32 theIndex)
  837. {
  838.     Size            mySize;
  839.     UInt32            myID = kQTVRUtils_InvalidHotSpotID;
  840.     UInt32            *myIDPtr;
  841.                 
  842.     // make sure the instance and hot spot list are non-NULL
  843.     if ((theInstance == NULL) || (theHotSpotIDs == NULL))
  844.         return(myID);
  845.     
  846.     // make sure that the index is valid    
  847.     mySize = GetHandleSize(theHotSpotIDs);
  848.     if (theIndex >= (mySize / sizeof(UInt32)))
  849.         return(myID);
  850.  
  851.     myIDPtr = (UInt32 *)*theHotSpotIDs;
  852.     myID = myIDPtr[theIndex];
  853.     return(myID);
  854. }
  855.  
  856.  
  857. //////////
  858. //
  859. // QTVRUtils_GetHotSpotType
  860. // Return the type of the hot spot having the specified hot spot ID in the specified node.
  861. //
  862. // NOTE: This function is semi-redundant, given QTVRGetHotSpotType; it's included here for illustrative purposes only.
  863. // (Note, however, that QTVRGetHotSpotType returns types only for hot spots in the current node; here we do any node!)
  864. //
  865. //////////
  866.  
  867. OSErr QTVRUtils_GetHotSpotType (QTVRInstance theInstance, UInt32 theNodeID, UInt32 theHotSpotID, OSType *theHotSpotType)
  868. {
  869.     QTVRHotSpotInfoAtom        myHotSpotAtomData;
  870.     OSErr                    myErr = noErr;
  871.     
  872.     // make sure we always return some meaningful value
  873.     *theHotSpotType = kQTVRHotSpotUndefinedType;
  874.     
  875.     // get the hot spot information atom data
  876.     myErr = QTVRUtils_GetHotSpotAtomData(theInstance, theNodeID, theHotSpotID, &myHotSpotAtomData);
  877.     if (myErr == noErr)
  878.         *theHotSpotType = EndianU32_BtoN(myHotSpotAtomData.hotSpotType);        // return the hot spot type
  879.     
  880.     return(myErr);
  881. }
  882.  
  883.  
  884. //////////
  885. //
  886. // QTVRUtils_GetHotSpotName
  887. // Return the name of the hot spot having the specified hot spot ID in the specified node.
  888. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  889. //
  890. //////////
  891.  
  892. char *QTVRUtils_GetHotSpotName (QTVRInstance theInstance, UInt32 theNodeID, UInt32 theHotSpotID)
  893. {
  894.     QTVRHotSpotInfoAtom        myHotSpotAtomData;
  895.     char                    *myHotSpotName = NULL;
  896.     OSErr                    myErr = noErr;
  897.     
  898.     // get the hot spot information atom data
  899.     myErr = QTVRUtils_GetHotSpotAtomData(theInstance, theNodeID, theHotSpotID, &myHotSpotAtomData);
  900.     if (myErr == noErr) {
  901.         QTAtomID                myNameAtomID;
  902.         
  903.         // get the atom ID of the name string atom
  904.         myNameAtomID = EndianU32_BtoN(myHotSpotAtomData.nameAtomID);
  905.         
  906.         if (myNameAtomID != 0) {
  907.             QTAtomContainer        myNodeInfo;
  908.             QTAtom                myHSParentAtom;
  909.             QTAtom                myHSAtom;
  910.             QTAtom                myNameAtom = 0;
  911.             
  912.             // version 2.0 documentation says that the hot spot name is contained in a string atom
  913.             // that is a sibling of the hot spot atom (that is, a child of the hot spot parent atom);
  914.             // some other documents indicate that a string atom is always a sibling of the atom that
  915.             // contains the reference (in this case, a sibling of the hot spot information atom, and
  916.             // hence a child of the hot spot atom); we will look first in the hot spot atom and then
  917.             // in the hot spot parent atom. The version 2.1 documentation corrects the earlier error.
  918.             // Mea culpa!
  919.  
  920.             // get the hot spot parent atom and the hot spot atom
  921.             myErr = QTVRGetNodeInfo(theInstance, theNodeID, &myNodeInfo);
  922.             if (myErr == noErr) {
  923.                 myHSParentAtom = QTFindChildByID(myNodeInfo, kParentAtomIsContainer, kQTVRHotSpotParentAtomType, 1, NULL);
  924.                 if (myHSParentAtom != 0) {
  925.                     myHSAtom = QTFindChildByID(myNodeInfo, myHSParentAtom, kQTVRHotSpotAtomType, theHotSpotID, NULL);
  926.                     if (myHSAtom != 0) {
  927.                         QTAtom    myParentAtom;
  928.                         
  929.                         // look for a string atom that is a child of the hot spot atom
  930.                         myParentAtom = myHSAtom;
  931.                         myNameAtom = QTFindChildByID(myNodeInfo, myParentAtom, kQTVRStringAtomType, theHotSpotID, NULL);
  932.                         if (myNameAtom == 0) {
  933.                             // no such atom in the hot spot atom; look in the hot spot parent atom
  934.                             myParentAtom = myHSParentAtom;
  935.                             myNameAtom = QTFindChildByID(myNodeInfo, myParentAtom, kQTVRStringAtomType, theHotSpotID, NULL);
  936.                         }
  937.                         
  938.                         if (myNameAtom != 0)
  939.                             myHotSpotName = QTVRUtils_GetStringFromAtom(myNodeInfo, myParentAtom, myNameAtomID);
  940.                     }
  941.                 }
  942.             }
  943.             
  944.             QTDisposeAtomContainer(myNodeInfo);
  945.         }
  946.     }
  947.  
  948.     return(myHotSpotName);
  949. }
  950.  
  951.  
  952. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  953. //
  954. // Miscellaneous utilities.
  955. //
  956. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  957.  
  958.  
  959. //////////
  960. //
  961. // QTVRUtils_Point3DToPanAngle
  962. // Return the QTVR pan angle for a given QD3D point.
  963. // 
  964. //////////
  965.  
  966. float QTVRUtils_Point3DToPanAngle (float theX, float theY, float theZ)
  967. {
  968. #pragma unused(theY)
  969.  
  970.     float    myPan;
  971.     
  972.     if (theZ != 0.0) {
  973.         // note that atan always returns angles in the range -π/2 to π/2
  974.         myPan = atan(theX / theZ);
  975.         myPan = (theZ > 0) ? myPan + kVRPi : myPan;
  976.     } else {
  977.         myPan = (theX > 0) ? kVR3PiOver2 : kVRPiOver2;
  978.     }
  979.     
  980.     // make sure myPan is positive
  981.     while (myPan < 0.0)
  982.         myPan += kVR2Pi;
  983.  
  984.     return(myPan);
  985. }
  986.  
  987.  
  988. //////////
  989. //
  990. // QTVRUtils_Point3DToTiltAngle
  991. // Return the QTVR tilt angle for a given QD3D point.
  992. // 
  993. //////////
  994.  
  995. float QTVRUtils_Point3DToTiltAngle (float theX, float theY, float theZ)
  996. {
  997.     float            myTilt;
  998.     float            myDistance;
  999.     TQ3Point3D        myPoint;
  1000.     
  1001.     myPoint.x = theX;
  1002.     myPoint.y = theY;
  1003.     myPoint.z = theZ;
  1004.     
  1005.     myDistance = QTVRUtils_GetDistance(myPoint);
  1006.     if (myDistance != 0.0)
  1007.         myTilt = asin(theY / myDistance); 
  1008.     else
  1009.         myTilt = 0.0;
  1010.     
  1011.     return(myTilt);
  1012. }
  1013.  
  1014.  
  1015. //////////
  1016. //
  1017. // QTVRUtils_PanAngleToPoint3D
  1018. // Return a unit vector for a given QTVR pan angle.
  1019. //
  1020. // The pan angle is expected to be in radians.
  1021. // 
  1022. //////////
  1023.  
  1024. void QTVRUtils_PanAngleToPoint3D (float thePanAngle, float *theX, float *theZ)
  1025. {
  1026.     // sin and cos are continuous functions and have no limits on input range;
  1027.     // output range is always -1..1
  1028.     *theX = sin(thePanAngle);
  1029.     *theZ = -cos(thePanAngle);
  1030. }
  1031.  
  1032.  
  1033. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  1034. //
  1035. // Node callback utilities.
  1036. //
  1037. // Use these to obtain standard behaviors when entering or exiting nodes.
  1038. //
  1039. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  1040.  
  1041. //////////
  1042. //
  1043. // QTVRUtils_StandardEnteringNodeProc
  1044. // A standard procedure for entering a new node.
  1045. //
  1046. // This function performs actions that many applications will want done when entering a new node:
  1047. //    * display back button only if multinode movie
  1048. //    * display show-hot-spot button only if there are hotspots
  1049. //    * display the translate button only for object nodes that can translate
  1050. //    * (this space for rent)
  1051. //
  1052. //////////
  1053.  
  1054. PASCAL_RTN OSErr QTVRUtils_StandardEnteringNodeProc (QTVRInstance theInstance, long theNodeID, MovieController theMC)
  1055. {
  1056. #pragma unused(theNodeID)
  1057.  
  1058.     OSErr        myErr = noErr;
  1059.  
  1060.     if ((theInstance == NULL) || (theMC == NULL))
  1061.         return(paramErr);
  1062.         
  1063.     /////// 
  1064.     // all nodes
  1065.     /////// 
  1066.         
  1067.     // display the back button only if it's a multinode movie
  1068.     if (QTVRUtils_IsMultiNode(theInstance))
  1069.         QTUtils_ShowControllerButton(theMC, (long)mcFlagQTVRSuppressBackBtn);
  1070.     else
  1071.         QTUtils_HideControllerButton(theMC, (long)mcFlagQTVRSuppressBackBtn);
  1072.  
  1073.     // display the show-hot-spot button only if there are hotspots in the node
  1074.     if (QTVRUtils_IsHotSpotInNode(theInstance))
  1075.         QTUtils_ShowControllerButton(theMC, (long)mcFlagQTVRSuppressHotSpotBtn);
  1076.     else
  1077.         QTUtils_HideControllerButton(theMC, (long)mcFlagQTVRSuppressHotSpotBtn);
  1078.  
  1079.     /////// 
  1080.     // panoramic nodes
  1081.     /////// 
  1082.     
  1083.     if (QTVRUtils_IsPanoNode(theInstance)) {
  1084.     
  1085.         // hide the translate button
  1086.         QTUtils_HideControllerButton(theMC, (long)mcFlagQTVRSuppressTranslateBtn);
  1087.         
  1088.     } else {
  1089.     
  1090.     /////// 
  1091.     // object nodes
  1092.     /////// 
  1093.         
  1094.         // show the translate button, but only if translation is available
  1095.         if (QTVRUtils_IsTranslateAvailable(theInstance))
  1096.             QTUtils_ShowControllerButton(theMC, (long)mcFlagQTVRSuppressTranslateBtn);
  1097.         else
  1098.             QTUtils_HideControllerButton(theMC, (long)mcFlagQTVRSuppressTranslateBtn);
  1099.     }
  1100.     
  1101.     return(myErr);
  1102. }
  1103.  
  1104.  
  1105. //////////
  1106. //
  1107. // QTVRUtils_StandardLeavingNodeProc
  1108. // A standard procedure for leaving a node.
  1109. // This function performs actions that many applications will want done when leaving a node:
  1110. //    * (this space for rent)
  1111. //
  1112. // We assume that when this procedure is called, the application has decided NOT to cancel the move;
  1113. // accordingly, we always return false in theCancel.
  1114. //
  1115. //////////
  1116.  
  1117. PASCAL_RTN OSErr QTVRUtils_StandardLeavingNodeProc (QTVRInstance theInstance, long fromNodeID, long toNodeID, Boolean *theCancel, MovieController theMC)
  1118. {
  1119. #pragma unused(fromNodeID, toNodeID)
  1120.  
  1121.     OSErr        myErr = noErr;
  1122.  
  1123.     if ((theInstance == NULL) || (theMC == NULL))
  1124.         return(paramErr);
  1125.     
  1126.     // nothing yet....
  1127.  
  1128.     *theCancel = false;
  1129.     return(myErr);
  1130. }
  1131.  
  1132.